/*#include "copyright.h"
#include "system.h"
#include "network.h"
#include "post.h"
#include "interrupt.h"
*/
#include "nachosServer.h"

using namespace std;

//#define MAX_LOCKSANDCOND (20000)	//limit of all Conditions and locks//check //100100
//#define SENDERROR sprintf(Msg->outData,"%d",-1); BuildMsg(Msg, 1); SendMsg(Msg)

int CreateLock(char* name) {

	printf("...in server-CreateLock\n");//100100
	
	//check whether there is the same lock in locks list or not
	int index = -1;     
    for(int i=0; i<lockCounter; i++) { 
       if(locks[i]->owned == -1) 
         continue; 
       //check whether there is the same name or not 
       if(strcmp(locks[i]->name, name) == 0) { 
           index = i; 
           break; 
       } 
    } 
   //if there is the same lock in locks list, return its index.
   if( index != -1) 
     return index; 
      
   //if the same name is not found, create the new lock. 
    if(lockCounter > maxNumOfLock){ 
		printf("server: error occurredin CreateLock. Too many locks were created.\n");
		//100100 check     send error message 
		return -1; 
     } 
     else { 
         index = lockCounter; 
         lockCounter++; 
     }   
	
   //actually create the lock in the array 
   SynchStruct *newLock = new SynchStruct; 
   newLock->name = name; 
   newLock->owned = 0;
   newLock->howManyAccessed = 0;
   newLock->waitQueues = new List();
   locks[index] = newLock; 
  
   printf("Returning %d\n", index); 
   return index;
  
}

int Acquire(ClientStruct *cStruct) {
	
	printf("...in server-Acquire\n");//100100

	//Lock open send message   
   int index = cStruct->synchID;
   
	//check whether the index is out of bound or not
	if (index < 0 || index > maxNumOfLock-1 || index > lockCounter ) {//if index is not valid
		printf("server: an error occurred. acquire in server. Lock index,%d is less than 0 or it is out of bounds\n", index);
		//check send error message //100100
		return -1;
	}

	//if lock does not exist
	if(locks[index]==NULL) {
		printf("server: an error occurred\n");
		//check send error message //100100
		return -1;
	}

	//if the index is valid...
	//if the lock is avaliable
   if(locks[index]->owned ==0){ 
	   locks[index]->howManyAccessed++;
       locks[index]->owned =1; //own this lock
       locks[index]->clientID = cStruct->clientID; 
		
	   //100100 send reply message
       return cStruct->clientID; //return client's machine id
   } 
   else //lock is busy
     { 
       if(locks[index]->clientID == cStruct->clientID) 
         { 
           return -1; 
         } 
        
       printf("Appending client to lock wait %d\n",cStruct->clientID); 

	   printf("---index: %d---\n", index);//100100
	  
	  locks[index]->howManyAccessed++;		 
	  locks[index]->waitQueues->Append((void *)cStruct); 
      // return -1; 
	  return index;//check 100100
     } 
   //Lock closed add to queue 

}

int Release(ClientStruct *cStruct){
 
	printf("...in server-Release\n");//100100
    
   //if someone waiting send message 
   int index = cStruct->synchID; 
  
   //verify that the index given does not exceed lock bounds
	if ((index < 0 || index > maxNumOfLock-1) || index > lockCounter) {
		printf("server: error occurred. Lock index%d\n", index);
		//check send msg //100100		
		return -1;
	}

	if(locks[index] == NULL){
		printf("server: error occurr. Lock index: %d", index);
		//check send msg //100100		
		return -1;
	}

   ClientStruct *newClientStruct = new ClientStruct(); 

   if(!cStruct->clientID == locks[index]->clientID) { 
	   printf("server: error occurr. Lock%d onwer is not this client: %d", index);
       return -1; 
   }

  //  printf("1======locks index: %d======\n", index);//100100

   if(!locks[index]->waitQueues->IsEmpty() ) {    

	   //printf("2============\n");//100100
		locks[index]->howManyAccessed--;
       newClientStruct = (ClientStruct *)locks[index]->waitQueues->Remove(); 
       locks[index]->clientID = newClientStruct->clientID; 
	   	   //      printf("2-2============\n");//100100

       return newClientStruct->clientID; 
   } 
   else { 
	       // printf("3============\n");//100100

     locks[index]->owned = 0; 
     return -1; 
   } 
   
}

 int CreateCondition(char* name) 
 { 
	printf("...in server-CreateCondition\n");//100100

   int index = -1;
	
   //find whether there is the same condition or not
   for(int i=0; i<CVCounter; i++) 
     { 
       if(cvs[i]->owned == -1) 
         continue; 
       //Check the name 
       if(strcmp(cvs[i]->name, name) == 0) 
         { 
           index = i; 
           break; 
         } 
     }   
   if( index != -1) 
     return index; 
     
   //Not found, so create a new lock. 
   //check the freeSpaces list first. Return those locations before actually iterating through bitmap 
   if(CVCounter > maxNumOfLock){ 
	   //check send msg //100100
       return -1; 
   } 
   else { 
	   index = CVCounter; 
       CVCounter++; 
   } 
   
   //actually create the lock in the array 
   SynchStruct *newCV = new SynchStruct; 
   newCV->name = name; 
   newCV->owned = 0; 
   cvs[index] = newCV; 
	cvs[index]->waitQueues = new List();

   return index; 
  
 } 

int Wait(ClientStruct *cStruct ) 
 { 
	printf("...in server-Wait\n");//100100
	printf("...cvID: %d\n",cStruct->cvID);//100100
	
    if(cvs[cStruct->cvID]->waitQueues->IsEmpty()) 
   //if(cvWaitQueues[cStruct->cvID]->IsEmpty()) //100100
     cvs[cStruct->cvID]->lockID = cStruct->synchID; 
    
   printf("Adding myself to wait queue. clinentID: %d",cStruct->clientID); 
   cvs[cStruct->cvID]->waitQueues->Append((void *)cStruct); 
   // cvWaitQueues[cStruct->cvID]->Append((void *)cStruct); //100100
   return Release(cStruct); 
  
 } 
  
 int Signal(ClientStruct* cStruct) { 

	 printf("...in server-Signal\n");//100100
   
   if(cvs[cStruct->cvID]->waitQueues->IsEmpty()) { 
       printf("waitQueue is empty\n"); 
       return -1; 
     } 
	
   if(cvs[cStruct->cvID]->lockID = cStruct->synchID) { 
       printf("Sorry our locks dont match\n"); 
       return -1; 
   } 
  
   ClientStruct* cs = (ClientStruct*) cvs[cStruct->cvID]->waitQueues->Remove(); 
   printf("Waking up cs %d.\n",cs->clientID); 
   return Acquire(cs); 
  
 } 

 int Broadcast(ClientStruct *cStruct) 
 { 
	printf("...in server-Broadcast\n");//100100

   int client; 
   while(!cvs[cStruct->cvID]->waitQueues->IsEmpty()) 
     { 
       //ClientStruct* cs = (ClientStruct*) cvWaitQueues[cStruct->cvID]->Remove(); 
       int x = Signal(cStruct); 
       
       if(x != -1) 
         client = x; 
     } 


	 printf("...end of server-Broadcast---\n");//100100

	 printf("...client: %d\n", client);//100100;

   return client; 
 } 
int DestroyLock(ClientStruct *cStruct) {
	
	printf("...in server-DestroyLock\n");//100100

	//get index of locks to delete this lock
   int index = cStruct->synchID; 

   printf("2.*************index: %d**********\n", index);//100100

   if (index < 0 || index > lockCounter-1) {
		printf("server: error occurred in  DestroyLock. Lock index%d is out of bounds')\n", index);
		//check send msg //100100
		return -1;
	}
	if(locks[index]==NULL) {
		printf("server: error occurred in DestroyLock.\n");
		//check send msg //100100
		return -1; 
	}
   //if the same name is not found, create the new lock. 
    if(lockCounter > maxNumOfLock){ 
		printf("server: error occurred in CreateLock. Too many locks were created.\n");
		//check send msg //100100
		return -1; 
     } 
     else { 
         index = lockCounter; 
         lockCounter++; 
     }   

	//delete lock and decrease the number of lock
	locks[index] = NULL;   
  
   return 1;
}

void server(int farAddr){

	printf("=========start server=============\n");//100100

	//initialize all data
	SynchStruct *emptyStruct = new SynchStruct;
    emptyStruct->name = ""; 
    emptyStruct->owned = -1; 

	//printf("~~~~~~~~~~~~~~~\n");//100100
/*	for(int i=0; i < maxNumOfLock; i++) 
		locks[i] = emptyStruct;   
*/	
/*	for(int i=0; i < maxNumOfLock; i++)
	   waitQueues[i] = new List(); 
*/   
  
	for(int i=0; i < maxNumOfCV; i++) 
     cvs[i] = emptyStruct; 

    for(int i=0; i < maxNumOfCV; i++) 
      cvWaitQueues[i] = new List();; 
  
  // lockCounter = 0; 
  // CVCounter = 0;

///////////////////////////
  PacketHeader outPktHdr, inPktHdr; 
   MailHeader outMailHdr, inMailHdr; 
   char buffer[MaxMailSize]; //Maximum is 40 bytes
   char *data= new char; 
   string temp; 
   stringstream ss; 


   while(true){ 
      
     printf("Server started, waiting for synch object requests.\n"); 
      
     postOffice->Receive(0, &inPktHdr, &inMailHdr, buffer); 
     printf("Got request %s from %d, bos %d\n", buffer, inPktHdr.from, inMailHdr.from); 
     fflush(stdout); 
      
     outPktHdr.from = 0; 
     outMailHdr.from = 0; 
  
     ss.clear(); 
     ss.str(buffer); //get client's request syscall

	 //initialize client infomation
     ClientStruct *cs = new ClientStruct; 
     cs->synchID = -1; 
     cs->cvID = -1; 
     cs->clientID = -1; 
     
     //Do the Work 
     char* name = new char; 
     int lockNum, client, cvNum; 
     char request, space; 
     ss >> request; 
     //    ss >> space; //100100
     switch(request) 
       { 
       case '1': //Create Lock          
         printf("server: recieved CreateLock request.\n"); //100100
         ss >> name; //get the name 
         printf("lock name: %s\n",name); 
         ss.clear(); //blank the string stream 
         //ss << nsm->createLock(name); //Create returns the id of the lock 
         ss.str(""); 
         ss <<  CreateLock(name);
         ss >> data; 
         printf("SS stuff happened %s.\n",data); 
         //make the outgoing message 
         outPktHdr.to = inPktHdr.from; 
         outMailHdr.to = inMailHdr.from; 
         outMailHdr.length = strlen(data) +1; 
         break; 
	 
	   case '2': //Create Condition 
         //takes 1 string 
         printf("Server recieved Create Condition request.\n"); 
         ss >> name; //get the name 
         ss.clear(); //blank the string stream 
         ss << CreateCondition(name); //Create returns the id of the conditon 
         ss >> data; 
         //make the outgoing message 
         outPktHdr.to = inPktHdr.from; 
         outMailHdr.to = inMailHdr.from; 
         outMailHdr.length = strlen(data) +1; 
         break; 

       case '3': //Acquire 
         //takes 1 int 
         printf("server: recieved AcquireLock request.\n"); 
         ss >> lockNum; //get the lock number 
         printf("server: LockNumber is %d\n",lockNum); 
         //ss.str(""); //clear the stream 
         ss.clear(); 
         ss.str(""); 
         //set up clientStruct to pass as parameter 
         cs->clientID = inMailHdr.from; 
         printf("client ID: %d \n",cs->clientID); 
         cs->synchID = lockNum; 
         //ss <<  nsm->acquire(cs); //acquire returns the id of the client who got the lock 
         //      printf("Client: %d", c); 
         //      ss << c; 
         //ss >> client; 
         client = Acquire(cs); 
         //printf("Client: %s", client); 
         //make the outgoing message (to will be -1 if did not get lock) 
         outPktHdr.to = client; 
         outMailHdr.to = client; 
         sprintf(data,"%d",lockNum); 
         //data = "You got the lock after Acquire\n"; 
         outMailHdr.length = strlen(data) +1; 
         break; 
  
       case '4': //Release 
         //takes 1 int 
         printf("Server recieved Release request.\n"); 
         ss >> lockNum; //get the lock number 
         ss.str(""); //clear the stream 
         //set up clientStruct to pass as parameter 
         cs->clientID = inMailHdr.from;  
         cs->synchID = lockNum; 
         //ss << nsm->release(cs); //acquire returns the id of the client who got the lock 
         //ss >> client; 
         client = Release(cs);   
         printf("Client value: %d\n",client); 
         //make the outgoing message (to will be -1 if did not get lock) 
         outPktHdr.to = client; 
         outMailHdr.to = client; 
         sprintf(data,"%d",lockNum); 
         //data = "You got the lock after Release\n"; 
         outMailHdr.length = strlen(data) +1; 
         break; 
  
       case '5': //Wait 
         //takes 2 int 
         printf("Server recieved Wait request.\n"); 
         ss >> cvNum >> space >> lockNum; //get the 2 parameters 
         //set up clientStruct 
         cs->clientID = inMailHdr.from; 
         cs->synchID = lockNum; 
         cs->cvID = cvNum; 
         //ss << nsm->wait(cs); //returns what the release returns 
         //ss >> client; 
         client = Wait(cs); 
         //make the outgoing message (to will be -1 if did not get lock) 
         outPktHdr.to = client; 
         outMailHdr.to = client; 
         sprintf(data,"%d",client);       
         //data = "You got the lock after Wait\n"; 
         outMailHdr.length = strlen(data) +1; 
         break; 
 
       case '6': //Signal 
         //takes 2 int 
         printf("Server recieved Signal request.\n"); 
         ss >> cvNum >> space >> lockNum; //get the 2 parameters 
         //set up clientStruct 
         cs->clientID = inMailHdr.from; 
         cs->synchID = lockNum; 
         cs->cvID = cvNum; 
         //ss << nsm->signal(cs); //returns what the acquire returns 
         //ss >> client; 
         client = Signal(cs); 
         //make the outgoing message (to will be -1 if did not get lock) 
         outPktHdr.to = client; 
         outMailHdr.to = client; 
         data = "You got the lock after Signal\n"; 
         outMailHdr.length = strlen(data) +1; 
         break; 
  
       case '7': //Broadcast 
         //takes 2 int 
         printf("Server: recieved Broadcast request.\n"); 
         ss >> cvNum >> space >> lockNum; //get the 2 parameters 
         //set up clientStruct 
         cs->clientID = inMailHdr.from; 
         cs->synchID = lockNum; 
         cs->cvID = cvNum; 
         //ss << nsm->signal(cs); //returns what the acquire returns 
         //ss >> client; 
         client = Broadcast(cs); 

		 printf("...client: %d\n", client);//100100;

         //make the outgoing message (to will be -1 if did not get lock) 
         outPktHdr.to = client; 
         outMailHdr.to = client; 
         data = "You got the lock after Broadcast\n"; 
         outMailHdr.length = strlen(data) +1; 
         break; 

	     case '8': //DestroyLock 
         printf("Server: received DestroyLock request.\n"); 
         ss >> lockNum; //get the lock number 
         ss.str(""); //clear the stream 
         //set up clientStruct to pass as parameter 
         cs->clientID = inMailHdr.from;  
         cs->synchID = lockNum; 
         client = DestroyLock (cs);   
         printf("Client value: %d\n",client); 
         //make the outgoing message (to will be -1 if did not get lock) 
         outPktHdr.to = client; 
         outMailHdr.to = client; 
         sprintf(data,"%d",lockNum); 
         //data = "You got the lock after Release\n"; 
         outMailHdr.length = strlen(data) +1; 
         break; 
  
       default: 
         printf("Wrong request %c\n", request); 
         break; 
       } 
      
     printf("End of swtich\n"); 
     //Reply to the client 
     if(outPktHdr.to != -1)  
       { 
         printf("Sending packet.\n"); 
         //      printf("Data: %s, outPktHdr.to: %d, outMailHrd.to: %d, outPktHdr.from: %d, outMailHdr.length: %d \n", data, outPktHdr.to,outMailHdr.to, outPktHdr.from, outMailHdr.length); 
       bool success = postOffice->Send(outPktHdr, outMailHdr, data); 
       printf("Sent packet\n"); 
       if(!success){ 
         printf("postOffice send failed. Terminating...\n"); 
         interrupt->Halt(); 
       } 
     } 
   } 
    
   interrupt->Halt(); 














///////////////////////////////////////
	delete locks; 
    //delete freeLockSpaces; //100100
    delete cvs; 
    //delete freeCVSpaces; 


	interrupt->Halt();
//	return;

}
